﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows;
using System.ComponentModel;
using System.Threading;

namespace JAAF.UI.WPF
{
    /// <summary>
    /// An decorator control that provides <see cref="IView">view</see> functionality to any WPF
    /// control it contains.
    /// It can be used for runtime hosting an arbitrary piece of UI to a <see cref="Viewspace"/>
    /// without implementing the <see cref="IView"/> interface on the UI piece itself.
    /// </summary>
    public class ViewAdapter : ContentControl, IView
    {
        #region Dependency Property Registration

        public static DependencyProperty TitleProperty = DependencyProperty.Register("Title", typeof(string), typeof(ViewAdapter));

        public static DependencyProperty DocumentationProperty = DependencyProperty.Register("Documentation", typeof(string), typeof(ViewAdapter));

        #endregion


        #region Instance Data

        /// <summary>
        /// The UIProcess this view is bound to
        /// </summary>
        private UIProcess m_oProcess;

        private string m_sName;

        private Window m_oParentWindow;

        #endregion


        #region Events

        public event EventHandler ViewActivated;

        public event EventHandler ViewDeactivated;

        public event System.ComponentModel.CancelEventHandler ViewClosing;

        public event EventHandler ViewClosed;

        #endregion


        #region Initialization

        /// <summary>
        /// Creates a new instance of a <see cref="ViewAdapter"/> for a WPF <see cref="FrameworkElement"/>.
        /// </summary>
        /// <param name="_oHostedUI">
        /// The WPF element that will be adapted to the <see cref="IView"/>interface.
        /// </param>
        public ViewAdapter(FrameworkElement _oHostedUI)
        {
            //m_oHostedCtrl = _oHostedControl;
            if (!string.IsNullOrWhiteSpace(_oHostedUI.Name))
                m_sName = _oHostedUI.Name;
            else
                m_sName = _oHostedUI.GetType().Name;

            Window oWin = _oHostedUI as Window;
            if (oWin != null)
            {
                _oHostedUI = (FrameworkElement)oWin.Content;
                oWin.Content = null;
                m_oParentWindow = oWin;

                this.Title = oWin.Title;
            }

            this.Content = _oHostedUI;

            this._RegisterEvents();
        }


        /// <summary>
        /// Registers the events of the hosted control
        /// </summary>
        private void _RegisterEvents()
        {
            this.HostedView.GotFocus += _HostedView_GotFocus;
            this.HostedView.LostFocus -= _HostedView_LostFocus;
        }

        /// <summary>
        /// Handles the GotFocus event of the hosted FrameworkElement
        /// and fires the <see cref="IView.ViewActivated"/> event.
        /// </summary>
        private void _HostedView_GotFocus(object sender, RoutedEventArgs e)
        {
            if (this.ViewActivated != null)
                this.ViewActivated(this, EventArgs.Empty);
        }

        /// <summary>
        /// Handles the LostFocus event of the hosted FrameworkElement
        /// and fires the <see cref="IView.ViewDeactivated"/> event.
        /// </summary>
        private void _HostedView_LostFocus(object sender, RoutedEventArgs e)
        {
            if (this.ViewDeactivated != null)
                this.ViewDeactivated(this, EventArgs.Empty);
        }


        protected override void OnContentChanged(object oldContent, object newContent)
        {
            base.OnContentChanged(oldContent, newContent);

            Control oCtrl = newContent as Control;
            if (oCtrl == null)
                return;


        }

        protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
        {
            base.OnRenderSizeChanged(sizeInfo);

            UIElement oContent = this.Content as UIElement;
            oContent.RenderSize = sizeInfo.NewSize;
        }

        #endregion


        #region Properties

        string IView.Name
        {
            get
            {
                return m_sName;
            }

            set
            {
                m_sName = value;
            }
        }

        public string Title
        {
            get
            {
                return (string)this.GetValue(TitleProperty);
            }
            set
            {
                this.SetValue(TitleProperty, value);
            }
        }

        public string Documentation
        {
            get
            {
                return (string)base.GetValue(DocumentationProperty);
            }
            set
            {
                this.SetValue(DocumentationProperty, value);
            }
        }

        public UIProcess Process
        {
            get { return m_oProcess; }
        }

        public FrameworkElement HostedView
        {
            get
            {
                return (FrameworkElement)this.Content;
            }
        }

        #endregion


        #region Methods

        public void Initialize(UIProcess _oOwningProcess)
        {
            m_oProcess = _oOwningProcess;
            this.DataContext = _oOwningProcess;

            // Remember that hosted windows are separated from their contents
            // So, we need to extra set the DataContext for those windows.
            if (m_oParentWindow != null)
                m_oParentWindow.DataContext = this.DataContext;
        }

        public void Refresh()
        {
            this.UpdateLayout();
        }

        public void Close()
        {
            if (this.ViewClosing != null)
            {
                CancelEventArgs oArgs = new CancelEventArgs();
                this.ViewClosing(this, oArgs);

                if (oArgs.Cancel)
                    return;
            }

            if (this.Parent != null)
            {
                ContentControl oContentCtrl = this.Parent as ContentControl;
                if (this.Parent is ContentControl)
                {
                    ((ContentControl)Parent).Content = null;
                }
                else if (this.Parent is Panel)
                {
                    ((Panel)this.Parent).Children.Remove(this);
                }
                else if (this.Parent is ItemsControl)
                {
                    ((ItemsControl)this.Parent).Items.Remove(this);
                }
                else
                {
                    throw new InvalidOperationException();
                }
            }

            this._OnViewClosed();
        }

        private void _OnViewClosed()
        {
            if (this.ViewClosed != null)
            {
                this.ViewClosed(this, EventArgs.Empty);
            }

            IDisposable oDispContent = this.Content as IDisposable;
            if (oDispContent != null)
                oDispContent.Dispose();
        }

        #endregion
    }
}
